import threading
from webob import Request
import webob
from qsiauth import models
from qsiauth.middleware import QuickSIAuthRequest
import re
import urlparse


class Error(Exception):
    """Base user exception."""

class QuickSIAuthError(Error):
    def __init__(self, msg):
        self.message = msg

def _abstract():
    raise NotImplementedError('You need to override this function')

class RegexValidator(object):
    regex = ''
    message = u'Enter a valid value.'
    code = 'invalid'

    def __init__(self, regex=None, message=None, code=None):
        if regex is not None:
            self.regex = regex
        if message is not None:
            self.message = message
        if code is not None:
            self.code = code

        if isinstance(self.regex, basestring):
            self.regex = re.compile(regex)

    def __call__(self, value):
        """
        Validates that the input matches the regular expression.
        """
        if not self.regex.search(unicode(value)):
            raise QuickSIAuthError(self.message)

email_re = re.compile(
    r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*"  # dot-atom
    r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-011\013\014\016-\177])*"' # quoted-string
    r')@(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?$', re.IGNORECASE)  # domain
url_re = re.compile(
        r'^https?://' # http:// or https://
        r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|' #domain...
        r'localhost|' #localhost...
        r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip
        r'(?::\d+)?' # optional port
        r'(?:/?|[/?]\S+)$', re.IGNORECASE)
slug_re = re.compile(r'^[-\w]+$')
ipv4_re = re.compile(r'^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$')
comma_separated_int_list_re = re.compile('^[\d,]+$')
_datere = r'\d{4}-\d{1,2}-\d{1,2}'
_timere = r'(?:[01]?[0-9]|2[0-3]):[0-5][0-9](?::[0-5][0-9])?'
alnum_re = re.compile(r'^\w+$')
alnumurl_re = re.compile(r'^[-\w/]+$')
ansi_date_re = re.compile('^%s$' % _datere)
ansi_time_re = re.compile('^%s$' % _timere)
ansi_datetime_re = re.compile('^%s %s$' % (_datere, _timere))


class BaseStrategy(object):

    error_class = QuickSIAuthError

    def __init__(self, app, config=None):
        self.app = app
        self.config = config

    def __call__(self, environ, start_response):
        req = QuickSIAuthRequest(environ)
        req._config = self.config
        req.provider_config = self.config['provider.{0}'.format(req.provider)]
        # TODO: This area needs to be reworked. There needs to be
        # a better way to handle errors
        try:
            redirect_uri = self.handle_request(req)
        except Exception, e:
            req.add_message(e.message, level='error')
            redirect_uri = self.config['login_uri']
        resp = webob.exc.HTTPTemporaryRedirect(location=redirect_uri)

        resp.request = req
        return resp(environ, start_response)

    @property
    def options(self):
        """
        Strategy Options must be overridden by sub-class
        :return:
        """
        return _abstract()

    def user_info(self, req):
        """

        :param req:
        :returns dict() Portable Contacts spec
        {
            'auth_id': User.generate_auth_id(req.provider, user['id']),
            'uid': user['id'], # Unique ID to the service provider
            'info': {
                'id': user.get('id'),
                'displayName': user.get('name'),
                'name': {
                    'formatted': user.get('name'),
                    'familyName': user.get('family_name'),
                    'givenName': user.get('given_name'),
                    'middleName': user.get('middle_name'),
                    'honorificPrefix': None,
                    'honorificSuffix': None,
                    },
                'birthday': user.get('birthday'),
                'gender': user.get('gender'),
                'tags': user.get('tags'), # List of tags
                'emails': [
                    {
                        'value': user.get('email'), # email
                        'type': user.get('email').get('type'), # home, work
                        'primary': user.get('email').get('primary'), # boolean
                    },
                ],
                'urls': [
                    {
                        'type': 'work',
                        'value': user.get('url'),
                        'primary': user.get('url').get('primary'),
                    },
                ],
                'phoneNumbers': [
                    {
                        'type': 'work',
                        'value': user.get('phone_number'),
                        'primary': True,
                    },
                ],
                "photos": [
                    {
                        "value": "http://sample.site.org/photos/12345.jpg",
                        "type": "thumbnail"
                    }
                ],
                "ims": [
                    {
                        "value": "plaxodev8",
                        "type": "aim"
                    }
                ],
                "addresses": [
                    {
                        "type": "home",
                        "streetAddress": "742 Evergreen Terrace\nSuite 123",
                        "locality": "Springfield",
                        "region": "VT",
                        "postalCode": "12345",
                        "country": "USA",
                        "formatted": "742 Evergreen Terrace\nSuite 123\nSpringfield, VT 12345 USA"
                    }
                ],
                "organizations": [
                    {
                        "name": "Burns Worldwide",
                        "title": "Head Bee Guy"
                    }
                ],
                "accounts": [
                    {
                        "domain": self.provider,
                        "userid": user['id']
                    }
                ],
                'utcOffset': user.get('utc_offset'),
                'locale': user.get('locale'),
                'verified': user.get('verified'),
                'nickname': user.get('username'),
                'location': user.get('location'), # user_location
                'aboutMe': user.get('bio'),
                'image': {
                    'url': user.get('id')),
                },

            },
            'extra': {
                'raw_info': user,
                }
        }
        """
        _abstract()

    def get_or_create_profile(self, auth_id, user_info, **kwargs):
        return models.UserProfile.get_or_create(auth_id, user_info, **kwargs)

    def handle_request(self, req):
        _abstract()

    def raise_error(self, message):
        raise QuickSIAuthError(msg=message)

    def validate_integer(self,value):
        try:
            int(value)
        except (ValueError, TypeError), e:
            raise QuickSIAuthError(msg='only integers allowed')

    def validate_email(self,value):
        if (not email_re.match(value)):
            raise QuickSIAuthError(msg='Kindly enter a valid email')
